package main

import (
	"fmt"
	"reflect"
)

//https://blog.csdn.net/secondtonone1/article/details/102855087
//反射
type Fly interface {
	fly() int
}
type User struct {
	Name string
	Age  int32
}

func (u *User) fly() int {
	return 1
}

type x = interface {
}

type Hero struct {
	name string
	id   int
}

func (h Hero) PrintData() {
	fmt.Println("Hero name is ", h.name, " id is ", h.id)
}

func (h Hero) SetName(name string) {
	h.name = name
}

func (h *Hero) SetName2(name string) {
	h.name = name
}

func (h *Hero) PrintData2() {
	fmt.Println("Hero name is ", h.name, " id is ", h.id)
}

func f1() {
	var num float64 = 13.14
	rtype := reflect.TypeOf(num)
	fmt.Println("reflect type is ", rtype)
	rvalue := reflect.ValueOf(num)
	fmt.Println("reflect value is ", rvalue)
	fmt.Println("reflect  value kind is", rvalue.Kind())
	fmt.Println("reflect type kind is", rtype.Kind())
	fmt.Println("reflect  value type is", rvalue.Type())

	// there is failed
	//if rvalue.Elem().CanSet() {
	//	fmt.Println("asigned value")
	//	rvalue.Elem().SetFloat(131.4)
	//}else {
	//	fmt.Println("dont allow modify")
	//}

	fmt.Println("========================")
	rptrvalue := reflect.ValueOf(&num)
	rptrtype := reflect.TypeOf(&num)
	fmt.Println("reflect value is ", rptrvalue)
	fmt.Println("reflect  value kind is", rptrvalue.Kind())
	fmt.Println("reflect type kind is", rptrtype.Kind())
	fmt.Println("reflect  value type is", rptrvalue.Type())
	if rptrvalue.Elem().CanSet() { // 必须是指针
		rptrvalue.Elem().SetFloat(131.4)
	}
	fmt.Println(num)

	//rvalue 为reflect包的Value类型
	//可通过Interface()转化为interface{}类型，进而转化为原始类型
	rawvalue := rvalue.Interface().(float64)
	fmt.Println("rawvalue is ", rawvalue)

	rawptrvalue := rptrvalue.Interface().(*float64)
	fmt.Println("rawptrvalue is ", *rawptrvalue)
}
func ReflectTypeValue(itf interface{}) {

	rtype := reflect.TypeOf(itf)
	fmt.Println("reflect type is ", rtype)
	rvalue := reflect.ValueOf(itf)
	fmt.Println("reflect value is ", rvalue)
	fmt.Println("reflect  value kind is", rvalue.Kind())
	fmt.Println("reflect type kind is", rtype.Kind())
	fmt.Println("reflect  value type is", rvalue.Type())
}
func f2() {
	ReflectTypeValue(Hero{name: "zack", id: 1})
	fmt.Println("===================")
	ReflectTypeValue(&Hero{name: "zack", id: 1})
}
func f3() {
	ReflectStructElem(Hero{name: "zack", id: 1})
	fmt.Println("================")
	ReflectStructPtrElem(&Hero{name: "Rolin", id: 20})
}
func f4() {
	hero := Hero{name: "zack", id: 1}
	ReflectStructMethod(hero)
	fmt.Println(hero)
}
func main() {
	user := &User{"lizhong", 123}
	value := reflect.ValueOf(user)
	//value := reflect.ValueOf(user)

	fmt.Println(value)
	typ := value.Type()
	fmt.Println(typ)
	//method := typ.Method(0).Name
	//fmt.Println(method)
	//f1()

	//f2()
	//f3()
	//f4()
	r := reflectNew(User{})
	fmt.Println(r.Interface()) //&{Lily 0}
	i := r.Interface().(*User) //&{Lily 0}
	fmt.Println(i)
}
func ReflectStructElem(itf interface{}) {
	rvalue := reflect.ValueOf(itf)
	for i := 0; i < rvalue.NumField(); i++ {
		elevalue := rvalue.Field(i)
		fmt.Println("element ", i, " its type is ", elevalue.Type())
		fmt.Println("element ", i, " its kind is ", elevalue.Kind())
		fmt.Println("element ", i, " its value is ", elevalue)
	}
}

/**
指针用Elem解引用
*/
func ReflectStructPtrElem(itf interface{}) {
	rvalue := reflect.ValueOf(itf)
	for i := 0; i < rvalue.Elem().NumField(); i++ {
		elevalue := rvalue.Elem().Field(i)
		fmt.Println("element ", i, " its type is ", elevalue.Type())
		fmt.Println("element ", i, " its kind is ", elevalue.Kind())
		fmt.Println("element ", i, " its value is ", elevalue)

		if rvalue.Elem().Field(1).CanSet() {
			rvalue.Elem().Field(1).SetInt(100)
		} else {
			fmt.Println("struct element 1 can't be changed")
		}
	}
}
func ReflectStructMethod(itf interface{}) {
	rvalue := reflect.ValueOf(itf)
	rtype := reflect.TypeOf(itf)
	for i := 0; i < rvalue.NumMethod(); i++ {
		methodvalue := rvalue.Method(i)
		fmt.Println("method ", i, " value is ", methodvalue)
		methodtype := rtype.Method(i)
		fmt.Println("method ", i, " type is ", methodtype)
		fmt.Println("method ", i, " name is ", methodtype.Name)
		fmt.Println("method ", i, " method.type is ", methodtype.Type)
	}

	//reflect.ValueOf 方法调用,无参方法调用
	fmt.Println(rvalue.Method(0).Call(nil))
	//有参方法调用
	params := []reflect.Value{reflect.ValueOf("Rolin")}
	fmt.Println(rvalue.Method(1).Call(params))
	//虽然修改了，但是并没有生效
	fmt.Println(rvalue.Method(0).Call(nil))
}

//反射创建新对象。
func reflectNew(target interface{}) reflect.Value {
	if target == nil {
		fmt.Println("参数不能未空")
		return reflect.Value{}
	}

	t := reflect.TypeOf(target)
	if t.Kind() == reflect.Ptr { //指针类型获取真正type需要调用Elem
		t = t.Elem()
	}

	newStruc := reflect.New(t)                            // 调用反射创建对象
	newStruc.Elem().FieldByName("Name").SetString("Lily") //设置值

	//newVal := newStruc.Elem().FieldByName("Name") //获取值
	return newStruc
}
